#!/usr/bin/env ts-node

/**
 * Project health check script
 * Validates the project structure, dependencies, and functionality
 */

import * as fs from 'fs';
import { execSync } from 'child_process';

interface CheckResult {
  name: string;
  status: 'pass' | 'fail' | 'warn';
  message: string;
  details?: string[];
}

class ProjectChecker {
  private results: CheckResult[] = [];

  /**
   * Run all checks
   */
  async runAllChecks(): Promise<void> {
    console.log('🔍 Running Project Health Checks');
    console.log('================================\n');

    await this.checkProjectStructure();
    await this.checkPackageJson();
    await this.checkTypeScript();
    await this.checkDependencies();
    await this.checkSourceFiles();
    await this.checkTests();
    await this.checkDocumentation();
    await this.checkExamples();
    await this.checkBuildSystem();

    this.displayResults();
  }

  /**
   * Check project structure
   */
  private async checkProjectStructure(): Promise<void> {
    const requiredDirs = [
      'src',
      'src/core',
      'src/patterns',
      'src/middleware',
      'src/enterprise',
      'src/performance',
      'src/utils',
      'tests',
      'examples',
      'docs',
    ];

    const requiredFiles = [
      'package.json',
      'tsconfig.json',
      'README.md',
      'LICENSE',
      'CHANGELOG.md',
      'CONTRIBUTING.md',
      'src/index.ts',
      'src/client.ts',
    ];

    const missingDirs = requiredDirs.filter(dir => !fs.existsSync(dir));
    const missingFiles = requiredFiles.filter(file => !fs.existsSync(file));

    if (missingDirs.length === 0 && missingFiles.length === 0) {
      this.addResult('pass', 'Project Structure', 'All required directories and files are present');
    } else {
      const details = [
        ...missingDirs.map(dir => `Missing directory: ${dir}`),
        ...missingFiles.map(file => `Missing file: ${file}`),
      ];
      this.addResult('fail', 'Project Structure', 'Missing required files or directories', details);
    }
  }

  /**
   * Check package.json
   */
  private async checkPackageJson(): Promise<void> {
    try {
      const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
      
      const requiredFields = ['name', 'version', 'description', 'main', 'types', 'scripts', 'dependencies'];
      const missingFields = requiredFields.filter(field => !packageJson[field]);

      const requiredScripts = ['build', 'test', 'lint', 'format'];
      const missingScripts = requiredScripts.filter(script => !packageJson.scripts?.[script]);

      if (missingFields.length === 0 && missingScripts.length === 0) {
        this.addResult('pass', 'Package.json', 'All required fields and scripts are present');
      } else {
        const details = [
          ...missingFields.map(field => `Missing field: ${field}`),
          ...missingScripts.map(script => `Missing script: ${script}`),
        ];
        this.addResult('fail', 'Package.json', 'Missing required fields or scripts', details);
      }
    } catch (error) {
      this.addResult('fail', 'Package.json', 'Failed to parse package.json');
    }
  }

  /**
   * Check TypeScript configuration
   */
  private async checkTypeScript(): Promise<void> {
    try {
      const tsconfig = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
      
      const requiredOptions = ['strict', 'esModuleInterop', 'skipLibCheck'];
      const missingOptions = requiredOptions.filter(option => 
        tsconfig.compilerOptions?.[option] !== true
      );

      if (missingOptions.length === 0) {
        this.addResult('pass', 'TypeScript Config', 'TypeScript configuration is properly set up');
      } else {
        this.addResult('warn', 'TypeScript Config', 'Some recommended options are missing', 
          missingOptions.map(opt => `Missing or disabled: ${opt}`));
      }
    } catch (error) {
      this.addResult('fail', 'TypeScript Config', 'Failed to parse tsconfig.json');
    }
  }

  /**
   * Check dependencies
   */
  private async checkDependencies(): Promise<void> {
    try {
      const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
      
      const requiredDeps = ['amqplib', 'zod', 'pino'];
      const requiredDevDeps = ['typescript', '@types/node', 'jest', 'eslint', 'prettier'];

      const missingDeps = requiredDeps.filter(dep => !packageJson.dependencies?.[dep]);
      const missingDevDeps = requiredDevDeps.filter(dep => !packageJson.devDependencies?.[dep]);

      if (missingDeps.length === 0 && missingDevDeps.length === 0) {
        this.addResult('pass', 'Dependencies', 'All required dependencies are present');
      } else {
        const details = [
          ...missingDeps.map(dep => `Missing dependency: ${dep}`),
          ...missingDevDeps.map(dep => `Missing dev dependency: ${dep}`),
        ];
        this.addResult('fail', 'Dependencies', 'Missing required dependencies', details);
      }
    } catch (error) {
      this.addResult('fail', 'Dependencies', 'Failed to check dependencies');
    }
  }

  /**
   * Check source files
   */
  private async checkSourceFiles(): Promise<void> {
    const coreFiles = [
      'src/core/config.ts',
      'src/core/connection-pool.ts',
      'src/core/message.ts',
      'src/core/handlers.ts',
      'src/core/producer.ts',
      'src/core/consumer.ts',
      'src/core/serializers.ts',
    ];

    const patternFiles = [
      'src/patterns/work-queue.ts',
      'src/patterns/pubsub.ts',
      'src/patterns/router.ts',
      'src/patterns/rpc.ts',
    ];

    const middlewareFiles = [
      'src/middleware/base.ts',
      'src/middleware/logging.ts',
      'src/middleware/metrics.ts',
    ];

    const allFiles = [...coreFiles, ...patternFiles, ...middlewareFiles];
    const missingFiles = allFiles.filter(file => !fs.existsSync(file));

    if (missingFiles.length === 0) {
      this.addResult('pass', 'Source Files', 'All core source files are present');
    } else {
      this.addResult('fail', 'Source Files', 'Missing source files', 
        missingFiles.map(file => `Missing: ${file}`));
    }
  }

  /**
   * Check tests
   */
  private async checkTests(): Promise<void> {
    const testFiles = [
      'tests/setup.ts',
      'tests/core/config.test.ts',
      'tests/core/message.test.ts',
    ];

    const missingTests = testFiles.filter(file => !fs.existsSync(file));

    if (missingTests.length === 0) {
      this.addResult('pass', 'Tests', 'Test files are present');
    } else {
      this.addResult('warn', 'Tests', 'Some test files are missing', 
        missingTests.map(file => `Missing: ${file}`));
    }
  }

  /**
   * Check documentation
   */
  private async checkDocumentation(): Promise<void> {
    const docFiles = [
      'README.md',
      'docs/API.md',
      'docs/GETTING_STARTED.md',
      'CHANGELOG.md',
      'CONTRIBUTING.md',
    ];

    const missingDocs = docFiles.filter(file => !fs.existsSync(file));

    if (missingDocs.length === 0) {
      this.addResult('pass', 'Documentation', 'All documentation files are present');
    } else {
      this.addResult('warn', 'Documentation', 'Some documentation files are missing', 
        missingDocs.map(file => `Missing: ${file}`));
    }
  }

  /**
   * Check examples
   */
  private async checkExamples(): Promise<void> {
    const exampleFiles = [
      'examples/basic.ts',
      'examples/enterprise.ts',
      'examples/performance.ts',
      'examples/monitoring.ts',
      'examples/advanced.ts',
    ];

    const missingExamples = exampleFiles.filter(file => !fs.existsSync(file));

    if (missingExamples.length === 0) {
      this.addResult('pass', 'Examples', 'All example files are present');
    } else {
      this.addResult('warn', 'Examples', 'Some example files are missing', 
        missingExamples.map(file => `Missing: ${file}`));
    }
  }

  /**
   * Check build system
   */
  private async checkBuildSystem(): Promise<void> {
    try {
      // Check if TypeScript compiles
      execSync('npx tsc --noEmit', { stdio: 'pipe' });
      this.addResult('pass', 'Build System', 'TypeScript compilation successful');
    } catch (error) {
      this.addResult('fail', 'Build System', 'TypeScript compilation failed');
    }
  }

  /**
   * Add a check result
   */
  private addResult(status: 'pass' | 'fail' | 'warn', name: string, message: string, details?: string[]): void {
    this.results.push({
      name,
      status,
      message,
      ...(details && { details })
    });
  }

  /**
   * Display all results
   */
  private displayResults(): void {
    console.log('\n📊 Check Results');
    console.log('================\n');

    const passed = this.results.filter(r => r.status === 'pass').length;
    const failed = this.results.filter(r => r.status === 'fail').length;
    const warned = this.results.filter(r => r.status === 'warn').length;

    this.results.forEach(result => {
      const emoji = {
        pass: '✅',
        fail: '❌',
        warn: '⚠️',
      }[result.status];

      console.log(`${emoji} ${result.name}: ${result.message}`);
      
      if (result.details && result.details.length > 0) {
        result.details.forEach(detail => {
          console.log(`   ${detail}`);
        });
      }
      console.log();
    });

    console.log('Summary:');
    console.log(`✅ Passed: ${passed}`);
    console.log(`⚠️  Warnings: ${warned}`);
    console.log(`❌ Failed: ${failed}`);
    console.log(`📊 Total: ${this.results.length}`);

    if (failed > 0) {
      console.log('\n❌ Project has critical issues that need to be addressed.');
      process.exit(1);
    } else if (warned > 0) {
      console.log('\n⚠️  Project has some warnings but is generally healthy.');
    } else {
      console.log('\n🎉 Project is in excellent health!');
    }
  }
}

// Run the checks
async function main(): Promise<void> {
  const checker = new ProjectChecker();
  await checker.runAllChecks();
}

if (require.main === module) {
  main().catch(console.error);
}

export { ProjectChecker };
